package encaps.utils.rendering;

import encaps.action.AbstractSearchAction;
import encaps.action.Action;
import encaps.action.BasicSearchAction;
import encaps.entities.OrderType;
import encaps.resources.Config;
import encaps.resources.Labels;
import encaps.resources.Response;
import encaps.utils.StringUtil;
import encaps.utils.html.*;
import java.util.List;
import org.jdom.Element;

public class TableParser implements Parser {

    private LinkFactory linkFactory;

    public TableParser() {
        linkFactory = new LinkFactory();
    }

    @Override
    public HTMLElement renderToHTML(Element response) {
        HTMLElementSequence result = new HTMLElementSequence();
        Element e = response.getChild(Response.TABLE);
        result.addContent(HeaderFactory.renderHeader(e.getChildTextTrim(Response.HEADER)));

        List columnHeaders = e.getChild(Response.COLUMN_HEADERS).getChildren();
        List rows = e.getChild(Response.ROWS).getChildren();
        if (rows.isEmpty()) {
            result.addContent(Labels.getLabel(Labels.NO_MATCHES_FOUND_MESSAGE));
            return result;
        }

        Element searchParams = e.getChild(Response.SEARCHING_PARAMETERS);

        HTMLTableElement table = new HTMLTableElement(rows.size(), ((Element) rows.get(0)).getChildren().size(), true);

        for (int i = 0; i < columnHeaders.size(); i++) {
            Element headerElement = (Element) columnHeaders.get(i);
            HTMLElement header = renderHeader(headerElement, searchParams);

            table.addHeader(i, header);
        }

        boolean firstLink = true;
        for (int i = 0; i < rows.size(); i++) {
            Element row = (Element) rows.get(i);
            List cells = row.getChildren();
            for (int j = 0; j < cells.size(); j++) {
                Element cell = (Element) cells.get(j);
                if (cell.getAttributeValue(Response.TYPE).equals(Response.TEXT)) {
                    table.addContentToCell(i, j, cell.getTextTrim());
                } else {
                    HTMLElement link = linkFactory.renderField(cell.getChild(Response.FIELD), false);
                    table.addContentToCell(i, j, link);
                    if (firstLink) {
                        firstLink = false;
                        link.addAttribute(HTML.CLASS, Styles.FIRST_LINK_IN_TABLE);
                    }
                }
            }
            firstLink = true;
        }

        result.addContent(table);
        result.addContent(HTMLElement.createBr());

        HTMLElement pagingPanel = renderPagingPanel(searchParams);
        result.addContent(pagingPanel);
        return result;
    }

    private HTMLElement renderHeader(Element headerElement, Element searchParameters) {
        String headerLabel = headerElement.getChildTextTrim(Response.COLUMN_HEADER_LABEL);
        String columnName = headerElement.getChildTextTrim(Response.COLUMN_NAME);
        if (StringUtil.isEmpty(columnName)) {
            return new HTMLElementSequence().addContent(headerLabel);
        }
        //Конструирование html-ссылки для сортировки
        HTMLElement headerLink = new HTMLElement(HTML.A);

        String entityType = searchParameters.getChildTextTrim(Response.ENTITY_TYPE);
        String actionName = searchParameters.getChildTextTrim(Response.ACTION_NAME);
        Element parametersElement = searchParameters.getChild(Response.PARAMETERS);
        List parameters = null;
        if (parametersElement != null) {
            parameters = parametersElement.getChildren(Response.PARAMETER);
        }

        String orderType = searchParameters.getChildTextTrim(Response.ORDER_TYPE);

        String href = createSearchingLiknAddress(null, parameters,
                entityType, actionName, columnName, orderType);
        headerLink.addAttribute(HTML.HREF, href);

        String arrowSign;
        String orderColumn = searchParameters.getChildTextTrim(Response.ORDER_COLUMN);
        if (StringUtil.isEmpty(orderType)
                || !columnName.equals(orderColumn)) {
            arrowSign = "";
        } else if (orderType.equalsIgnoreCase(OrderType.ASCENT.toString())) {
            arrowSign = "&nbsp;&nbsp; &#9650;";
        } else {
            arrowSign = "&nbsp;&nbsp; &#9660;";
        }
        headerLink.addContent(headerLabel + arrowSign);

        return headerLink;
    }

    private HTMLElement renderPagingPanel(Element searchParameters) {
        if (searchParameters == null) {
            return null;
        }
        //неведомая ёбаная хуйня))
        HTMLElementSequence pagingElement = new HTMLElementSequence();

        int pageCount = Integer.parseInt(searchParameters.getChildTextTrim(Response.PAGE_COUNT));
        int currentPage = Integer.parseInt(searchParameters.getChildTextTrim(Response.CURRENT_PAGE));
        int pagesRunningCount = Config.getPagesRunningCount();
        String entityType = searchParameters.getChildTextTrim(Response.ENTITY_TYPE);
        String actionName = searchParameters.getChildTextTrim(Response.ACTION_NAME);
        Element parametersElement = searchParameters.getChild(Response.PARAMETERS);
        List parameters = null;
        if (parametersElement != null) {
            parameters = parametersElement.getChildren(Response.PARAMETER);
        }
        String orderColumn = searchParameters.getChildTextTrim(Response.ORDER_COLUMN);
        String orderType = searchParameters.getChildTextTrim(Response.ORDER_TYPE);

        //Отрисовка левой половины номеров страниц
        int minShownPageNumber = currentPage - pagesRunningCount;
        if (minShownPageNumber > 1) {
            addLinkToPagingPanel(pagingElement, 1, currentPage, parameters, entityType, actionName, orderColumn, orderType);
            if (minShownPageNumber > 2) {
                pagingElement.addContent("... &nbsp;");
            }
            for (int i = minShownPageNumber; i <= currentPage; i++) {
                addLinkToPagingPanel(pagingElement, i, currentPage, parameters, entityType, actionName, orderColumn, orderType);
            }
        } else {
            for (int i = 1; i <= currentPage; i++) {
                addLinkToPagingPanel(pagingElement, i, currentPage, parameters, entityType, actionName, orderColumn, orderType);
            }
        }

        //Отрисовка правой половины номеров страниц
        int maxShownPageNumber = currentPage + pagesRunningCount;
        if (maxShownPageNumber < pageCount) {
            for (int i = currentPage + 1; i <= maxShownPageNumber; i++) {
                addLinkToPagingPanel(pagingElement, i, currentPage, parameters, entityType, actionName, orderColumn, orderType);
            }
            if (maxShownPageNumber < pageCount - 1) {
                pagingElement.addContent("... &nbsp;");
            }
            addLinkToPagingPanel(pagingElement, pageCount, currentPage, parameters, entityType, actionName, orderColumn, orderType);
        } else {
            for (int i = currentPage + 1; i <= pageCount; i++) {
                addLinkToPagingPanel(pagingElement, i, currentPage, parameters, entityType, actionName, orderColumn, orderType);
            }
        }
        HTMLElement pagingPanel = new HTMLElement(HTML.P);
        pagingPanel.addAttribute(HTML.CLASS, Styles.PAGING_PANEL);
        pagingPanel.addContent(pagingElement);
        return pagingPanel;

    }

    private void addLinkToPagingPanel(HTMLElement pagingPanel, int pageNumber,
            int currentPage, List parameters, String entityType,
            String actionName, String orderColumn, String orderType) {
        if (pageNumber == currentPage) {
            pagingPanel.addContent(pageNumber);
        } else {
            HTMLElement link = new HTMLElement(HTML.A);

            String href = createSearchingLiknAddress(pageNumber,
                    parameters, entityType, actionName,
                    orderColumn, orderType);


            link.addAttribute(HTML.HREF, href);
            link.addContent(pageNumber);
            pagingPanel.addContent(link);
        }
        pagingPanel.addContent(" &nbsp;");
    }

    private String createSearchingLiknAddress(Integer pageNumber,
            List parameters, String entityType, String actionName,
            String orderColumn, String orderType) {
        StringBuilder href = new StringBuilder();
        href.append(Config.getHomePage());
        href.append("?");
        href.append(Action.ACTION);
        href.append("=");
        href.append(actionName);
        if (!StringUtil.isEmpty(entityType)) {
            href.append("&");
            href.append(BasicSearchAction.ENTITY_TYPE);
            href.append("=");
            href.append(entityType);
        }
        if (!StringUtil.isEmpty(orderColumn)) {
            href.append("&");
            href.append(AbstractSearchAction.ORDER_COLUMN);
            href.append("=");
            href.append(orderColumn);
            //Костыль)
            if (pageNumber == null) {
                orderType = OrderType.getOppositeOrder(orderType).toString();
            }
            if (!StringUtil.isEmpty(orderType)) {
                href.append("&");
                href.append(AbstractSearchAction.ORDER_TYPE);
                href.append("=");
                href.append(orderType);
            }
        }
        if (parameters != null) {
            for (Object obj : parameters) {
                Element parameter = (Element) obj;
                String parameterName = parameter.getChildTextTrim(Response.NAME);
                String parameterValue = parameter.getChildTextTrim(Response.VALUE);
                href.append("&");
                href.append(parameterName);
                href.append("=");
                href.append(StringUtil.getValidValue(parameterValue));
            }
        }
        if (pageNumber != null) {
            href.append("&");
            href.append(BasicSearchAction.PAGE);
            href.append("=");
            href.append(pageNumber);
        }
        return href.toString();
    }
}
